#!/usr/bin/env python3
# coding=utf-8
# pip3.12 install -i https://mirrors.aliyun.com/pypi/simple aliyun-python-sdk-core aliyun-python-sdk-bssopenapi==1.7.20

import requests
import os
import json
import time
import requests
from datetime import datetime, timedelta
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ClientException, ServerException
from aliyunsdkcore.auth.credentials import AccessKeyCredential
from aliyunsdkbssopenapi.request.v20171214 import QueryBillRequest

access_key_id = os.environ.get('ALIYUN_MASTER_ACCESS_KEY_ID')
access_key_secret = os.environ.get('ALIYUN_MASTER_ACCESS_KEY_SECRET')

if not access_key_id or not access_key_secret:
    raise ValueError("环境变量ALIBABA_CLOUD_ACCESS_KEY_ID或ALIBABA_CLOUD_ACCESS_KEY_SECRET未设置")

client = AcsClient(
    access_key_id,
    access_key_secret,
    'ap-southeast-1'  # 请根据实际情况替换区域ID
)

yesterday = datetime.now() - timedelta(days=1)
yesterday_str = yesterday.strftime('%Y-%m-%d')

cost_dict = {}

# 初始化查询参数,先获取TotalCount
request_init = QueryBillRequest.QueryBillRequest()
request_init.set_BillingCycle(yesterday_str)
request_init.set_IsHideZeroCharge(True)
request_init.set_ProductCode("")
request_init.set_accept_format('json')
request_init.set_PageSize(1)  # 仅获取一页以得到TotalCount

service_name_mapping = {
    "Elastic Container Instance": "弹性容器实例",
    "ApsaraDB for Redis": "云数据库Redis版",
    "Elastic Compute Service": "弹性计算服务",
    "PolarDB": "PolarDB数据库",
    "Microservices Engine": "微服务引擎",
    "Server Load Balancer": "服务器负载均衡",
    "NAT Gateway": "NAT网关",
    "Elastic Block Storage": "弹性块存储",
    "Elastic IP Address": "弹性公网IP",
    "ApsaraDB RDS": "云数据库RDS",
    "Object Storage Service": "对象存储OSS",
    "CDN": "内容分发网络CDN",
}

def get_sorted_cost_summary(cost_dict):
    """
    返回一个有序的成本摘要字典
    """
    # 首先计算总成本
    total_cost = round(sum(cost_dict.values()), 2)
    # 排序并构造新的字典,包含总成本和其他费用项
    sorted_costs = {"昨天总成本": total_cost}
    sorted_costs.update({k: round(v, 2) for k, v in sorted(cost_dict.items(), key=lambda x: x[1], reverse=True)})
    return sorted_costs

try:
    start_time = time.time()
    
    response_init = client.do_action_with_exception(request_init)
    response_dict_init = json.loads(response_init)
    
    if response_dict_init.get('Success'):
        total_count = response_dict_init['Data']['TotalCount']
        page_size = 300
        current_page = 1
        
        while True:
            request = QueryBillRequest.QueryBillRequest()
            request.set_BillingCycle(yesterday_str)
            request.set_IsHideZeroCharge(True)
            request.set_ProductCode("")
            request.set_accept_format('json')
            request.set_PageNum(current_page)
            request.set_PageSize(page_size)
            
            response = client.do_action_with_exception(request)
            response_dict = json.loads(response)
            
            if response_dict.get('Success'):
                items = response_dict.get('Data', {}).get('Items', {}).get('Item', [])
                for item in items:
                    usage_start_time = item.get('UsageStartTime')
                    usage_end_time = item.get('UsageEndTime')
                    if usage_start_time.startswith(yesterday_str) and usage_end_time.startswith(yesterday_str):
                        product_name = item.get('ProductName')
                        cost = float(item.get('PretaxGrossAmount', 0.0))
                        
                        # 使用映射字典将英文服务名转换为中文
                        product_name_zh = service_name_mapping.get(product_name, product_name)
                        cost_dict[product_name_zh] = cost_dict.get(product_name_zh, 0.0) + cost
                
                # 判断是否已经处理完所有数据
                if current_page * page_size >= total_count:
                    break  # 所有数据处理完毕,退出循环
                else:
                    current_page += 1  # 否则,继续处理下一页
                
                print(f"page {current_page}, total records: {total_count}")
            else:
                error_message = response_dict.get('Message', '未知错误')
                print(f"查询费用失败: {error_message}")
                break

    else:
        error_message = response_dict_init.get('Message', '未知错误')
        print(f"查询总记录数失败: {error_message}")

    
    # print(f"\nExecution Time: {end_time - start_time:.2f} seconds")

except ClientException as e:
    print(f"客户端异常: {e}")
except ServerException as e:
    print(f"服务端异常: {e}")

# 计算并打印总成本及各项费用,进行四舍五入处理
# 调用函数获取排序后的成本摘要字典
cost_summary = get_sorted_cost_summary(cost_dict)


for key, value in cost_summary.items():
    if key == "昨天总成本":
        print(f"{key}: {value} 美元")
    else:
        print(f"{key}: {value} 美元")

# 返回成本摘要字典
print("\n返回的成本摘要字典为：")
print(cost_summary)

end_time = time.time()
print(f"Execution Time: {end_time - start_time:.2f} seconds")







WEBHOOK_URL = "https://open.larksuite.com/open-apis/bot/v2/hook/1da0d984-bd4f-4297-85f7-3ef01b377f14"
MSG_TYPE_INTERACTIVE = "interactive"  # 定义消息类型常量

def send_notification(message, color="red"):
    """
    发送飞书互动卡片通知。
    
    参数:
    - message (str): 通知内容,Markdown格式。
    - color (str): 通知颜色主题,默认为 "red",可选 "green"。
    """
    headers = {"Content-Type": "application/json"}
    template_color = "green" if color.lower() == "green" else "red"
    
    payload = {
        "msg_type": MSG_TYPE_INTERACTIVE,
        "card": {
            "config": {"wide_screen_mode": True},
            "elements": [{"tag": "markdown", "content": message}],
            "header": {
                "template": template_color,
                "title": {"content": "云费用通知" if color == "green" else "云费用告警", "tag": "plain_text"},
            },
        },
    }
    
    try:
        response = requests.post(WEBHOOK_URL, headers=headers, json=payload)
        response.raise_for_status()  # 如果不是200,抛出异常
    except requests.RequestException as e:
        print(f"发送通知时发生错误: {e}")
        return None
    
    return response


# 计算并打印总成本及各项费用后,添加发送飞书通知的逻辑
THRESHOLD_COST = 1000  # 设定费用阈值为500美元
total_cost_usd = cost_summary.get("昨天总成本", 0)
color = "red" if total_cost_usd > THRESHOLD_COST else "green"
message = (
    f"昨天总成本: {total_cost_usd} 美元\n\n"
    + "\n".join([f"{k}: {v} 美元" for k, v in cost_summary.items() if k != "昨天总成本"])
)

# 发送飞书通知
send_notification(message, color)